/**
 * Copyright (c) 2018-2028.
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.sailmi.oss.controller;

import com.sailmi.common.tool.api.R;
import com.sailmi.common.tool.utils.Func;
import com.sailmi.common.model.oss.GeneralFile;
import com.sailmi.oss.model.OssFile;
import com.sailmi.oss.props.OssProperties;
import com.sailmi.oss.provider.OssProvider;
import com.sailmi.oss.provider.OssProviderFactory;
import com.sailmi.oss.util.DbUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.tomcat.util.http.MimeHeaders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;

/**
 * 对象存储端点
 *
 * @author yzh
 */
@Tag(
	name = "文件传输接口",
	description = "文件传输接口"
)
@RestController
@RequestMapping("/oss")

//@Tag(value = "对象存储端点", tags = "对象存储端点")
public class OssController {
	private static final Logger log = LoggerFactory.getLogger(OssController.class);
	//初始化OSSProperties
	@Autowired
	OssProperties ossProperties;
	DbUtils dbUtils = new DbUtils();

	public OssController(OssProperties ossProperties, DbUtils dbUtils) {
		this.ossProperties = ossProperties;
		this.dbUtils = dbUtils;
	}

	/**
	 * 获取文件信息
	 *
	 * @param fileLink 对象名称
	 * @return InputStream
	 */
	@Operation(
		summary = "获取文件",
		description = "获取文件"
	)

	@GetMapping("/get-file")
	public void GetFile(@RequestParam("fileLink") String fileLink) {
		OssProvider ossProvider = OssProviderFactory.getOssProvider(ossProperties.getProviderDriver());
		//缺省为公共的库，后面为每一个企业指定库。
		String buckets = "public";
		ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = attributes.getRequest();
		HttpServletResponse response = attributes.getResponse();
		log.info("请求文件：" + fileLink);
		String fileName = fileLink.substring(fileLink.lastIndexOf("/")+1);
		OutputStream outputStream = null;
		try {
			outputStream = response.getOutputStream();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		InputStream fis = null;
		//获取文件
		log.info("通过原始文件名获取数据：" + fileLink);

		//判断图片是否已经经过Base64处理,不含后缀名
		String errInfo = "Unknown Error:";
		try {
			fis = ossProvider.getFile(buckets, fileLink);

			if (fis != null) {
				response.reset();
				response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
				response.setHeader("Content-Disposition","attachment;filename="+fileName);
				BufferedInputStream bufferedInputStream=new BufferedInputStream(fis);
				BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
				byte[] tranBytes = new byte[10240];
				int readLen =0;
				while((readLen=bufferedInputStream.read(tranBytes))!=-1){
					bufferedOutputStream.write(tranBytes,0,readLen);
				}
				bufferedInputStream.close();
				bufferedOutputStream.close();
				outputStream.flush();
				outputStream.close();
			}else{
				response.sendError(404);
			}
		} catch (Exception ec) {
			errInfo = errInfo.concat(ec.getMessage());
			log.error("通过原始文件名获取文件失败：" + fileLink);
		}finally {
			if (fis != null) {
				try {
					fis.close();
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
			if (outputStream != null) {
				try {
					outputStream.close();
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
			dbUtils.addFileVisitNum(fileLink);
		}
	}

	/**
	 * 获取文件信息
	 *
	 * @param fileLink 对象名称
	 * @return InputStream
	 */
	@Operation(
		summary = "获取文件",
		description = "获取文件"
	)

	@GetMapping("/file/{fileLink}")
	public HttpServletResponse File(@PathVariable("fileLink") String fileLink) {
		OssProvider ossProvider = OssProviderFactory.getOssProvider(ossProperties.getProviderDriver());
		System.out.println("get file from server proxy!");
		//缺省为公共的库，后面为每一个企业指定库。
		String buckets = "public";
		ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest request = attributes.getRequest();
		HttpServletResponse response = attributes.getResponse();
		String fileName = fileLink.substring(fileLink.lastIndexOf("/")+1);
		log.info("请求文件：" + fileLink);
		OutputStream outputStream = null;
		try {
			outputStream = response.getOutputStream();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		InputStream fis = null;
		log.info("通过原始文件名获取数据：" + fileLink);
		//判断图片是否已经经过Base64处理,不含后缀名
		try {
			fis = ossProvider.getFile(buckets, fileLink);
			if (fis != null) {
				response.setContentType("application/octet-stream");
				response.setHeader("Content-Disposition","attachment;filename="+fileName);
				int bufferLen = 1024;
				byte[] buffer = new byte[bufferLen];
				int readLen = fis.read(buffer);
				while (readLen > 0) {
					outputStream.write(buffer, 0, readLen);
					readLen = fis.read(buffer);
				}
			}
		} catch (Exception ec) {
			log.error("通过原始文件名获取文件失败：" + fileLink);
		}finally {
			if (fis != null) {
				try {
					fis.close();
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
			if (outputStream != null) {
				try {
					outputStream.close();
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
		}
		return response;
	}


	/**
	 * 获取文件信息
	 *
	 * @param fileName 对象名称
	 * @return InputStream
	 */
	@Operation(
		summary = "获取文件状态",
		description = "获取文件状态"
	)
	@GetMapping("/stat-file")
	public R<OssFile> statFile(@RequestParam String fileName) {
		String buckets = "public";
		OssProvider ossProvider = OssProviderFactory.getOssProvider(ossProperties.getProviderDriver());
		return R.data(ossProvider.statFile(buckets, fileName));
	}

	/**
	 * 获取文件相对路径
	 *
	 * @param fileName 存储桶对象名称
	 * @return String
	 */
	@Operation(
		summary = "获取文件路径",
		description = "获取文件路径"
	)
	@GetMapping("/file-path")
	public R<String> filePath(@RequestParam String fileName) {
		String buckets = "public";
		OssProvider ossProvider = OssProviderFactory.getOssProvider(ossProperties.getProviderDriver());
		return R.data(ossProvider.filePath(buckets, fileName));
	}


	/**
	 * 获取文件外链
	 *
	 * @param fileName 存储桶对象名称
	 * @return String
	 */
	@Operation(
		summary = "获取文件链接",
		description = "获取文件链接"
	)
	@GetMapping("/file-link")
	public R<String> fileLink(@RequestParam String fileName) {
		String buckets = "public";
		OssProvider ossProvider = OssProviderFactory.getOssProvider(ossProperties.getProviderDriver());
		return R.data(ossProvider.fileLink(buckets, fileName));
	}

	/**
	 * 上传文件
	 *
	 * @param file 文件
	 * @return ObjectStat
	 */
	@Operation(
		summary = "上传文件",
		description = "上传文件"
	)
	@PostMapping("/put-file")
	public R<GeneralFile> putFile(@RequestParam("file") MultipartFile file) {
		String buckets = "public";
		String fileName = file.getOriginalFilename();
		/*
		//截取
		String fileNameFirst = fileName.substring(0, fileName.lastIndexOf("."));
		String fileNameExt = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
		//获取新的文件名
		String newFileName = DateUtil.nowInMs();
		//为文件名增加随机码
		newFileName = newFileName.concat(StringUtil.random(3));
		//完成文件名组装
		fileName = newFileName.concat(".").concat(fileNameExt);

		 */
		GeneralFile generalFile = null;
		//存储文件
		OssProvider ossProvider = OssProviderFactory.getOssProvider(ossProperties.getProviderDriver());
		generalFile = ossProvider.putFile(buckets, fileName, file);
		log.debug("dataFile file link is:" + generalFile.getLink());
		log.debug("dataFile file name is:" + generalFile.getName());
		log.debug("dataFile file original name is:" + generalFile.getOriginalName());
		dbUtils.saveFileInfo(fileName,generalFile.getLink(),generalFile.getOriginalName(),generalFile.getSize());
		return R.data(generalFile);
	}


	/**
	 * 上传文件
	 *
	 * @param fileName 存储桶对象名称
	 * @param file     文件
	 * @return ObjectStat
	 */
	@Operation(
		summary = "上传文件并以指定名字存储",
		description = "上传文件并以指定名字存储"
	)
	@PostMapping("/put-file-by-name")
	public R<GeneralFile> putFile(@RequestParam String fileName, @RequestParam MultipartFile file) {
		String buckets = "public";
		GeneralFile generalFile = null;
		OssProvider ossProvider = OssProviderFactory.getOssProvider(ossProperties.getProviderDriver());
		try {
			generalFile = ossProvider.putFile(file.getOriginalFilename(), (MultipartFile) file.getInputStream());
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		return R.data(generalFile);
	}

	/**
	 * 删除文件
	 *
	 * @param fileLink 存储桶对象路径
	 * @return R
	 */
	@Operation(
		summary = "删除文件",
		description = "删除文件"
	)

	@PostMapping("/remove-file")
	public R removeFile(@RequestParam String fileLink) {
		String buckets = "public";
		OssProvider ossProvider = OssProviderFactory.getOssProvider(ossProperties.getProviderDriver());
		ossProvider.removeFile(buckets, fileLink);
		dbUtils.removeFile(fileLink);
		return R.success("操作成功");
	}

	/**
	 * 批量删除文件
	 *
	 * @param fileNames 存储桶对象名称集合
	 * @return R
	 */
	@Operation(
		summary = "批量删除文件",
		description = "批量删除文件"
	)
	@PostMapping("/remove-files")
	public R removeFiles(@RequestParam String fileNames) {
		String buckets = "public";
		OssProvider ossProvider = OssProviderFactory.getOssProvider(ossProperties.getProviderDriver());
		ossProvider.removeFiles(buckets, Func.toStrList(fileNames));
		return R.success("操作成功");
	}
}
